﻿using System;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Web;
using System.Windows.Forms;
using SG.Sys.Console.CommandProcessing;
using SG.Sys.Console.Process;
using SysProcess = System.Diagnostics.Process;

namespace SG.Sys.Console.View
{
    partial class ConsolePane
    {
        const string HttpProtocol = "http://";
        const string FileProtocol = "file://";

        private void PrintToTextBox(LineOutputEvent e)
        {
            AppendText(textOutput, e.Content,
                       new FormatOptions {IsPromptLine = e.IsPromptLine, AppendNewLine = e.TerminatedLineCount == 0});
        }

        private void AppendText(RichTextBox box, Entry entry)
        {
            AppendText(box, entry.ToString(), new FormatOptions{AppendNewLine = true, PrettyPrint = true});
        }


        enum PathType { None, Directory, File }
        private PathType ValidatePath(string path)
        {
            var type = PathType.None;

            if (File.Exists(path))
                type = PathType.File;

            if (Directory.Exists(path))
                type = PathType.Directory;

            return type;
        }

        private static string Linkify(string path, PathType type)
        {
            var terminatedDirectory = type == PathType.Directory && path.Last() != Path.DirectorySeparatorChar;
            return string.Format("{0}/{1}{2}",
                          FileProtocol,
                          HttpUtility.UrlPathEncode(path.Replace(Path.DirectorySeparatorChar, '/')),
                          terminatedDirectory ? "/" : "");
        }

        private void FormattedAppendText(RichTextBox box, string text, bool format)
        {
            box.AppendText(text);
        }

        public class FormatOptions
        {
            public bool AppendNewLine { get; set; }
            public bool IsPromptLine { get; set; }
            public bool PrettyPrint { get; set; }
        }

        private void AppendText(RichTextBox box, string text, FormatOptions options)
        {;
            var isPromptLine = options.IsPromptLine;
            var appendNewLine = options.AppendNewLine;

            Action<string, bool> textAdder =
                (pText, pFormat) => FormattedAppendText(box, pText, pFormat);

            if (box.ReadOnly)
            {
                var currentIndex = 0;
                
                do
                {
                    var boundaryChar = text[currentIndex] == '"' ? '"' : ' ';
                    var nextIndex = text.IndexOfAny(new []{boundaryChar, '\r', '\n', '\t'}, currentIndex);
                    var newLineBoundary = false;

                    string word;
                    if (isPromptLine)
                    {
                        nextIndex = text.Length - 1; 
                        word = text.Substring(0, nextIndex);
                    }
                    else
                    {
                        if (nextIndex < 0)
                        {
                            nextIndex = text.Length;
                            word = text.Substring(currentIndex);
                        }
                        else if (text[nextIndex] == '\r')
                        {
                            word = text.Substring(currentIndex, nextIndex - currentIndex);
                            nextIndex++;
                            newLineBoundary = true;
                        }
                        else
                        {
                            word = text.Substring(currentIndex, nextIndex - currentIndex);
                            newLineBoundary = text[nextIndex] == '\n';
                        }
                    }

                    var pathType = ValidatePath(word);
                    if (pathType != PathType.None)
                        textAdder(Linkify(word, pathType), false);
                    else
                        textAdder(word, options.PrettyPrint);

                    if (newLineBoundary)
                        textAdder("\n", false);
                    else if (nextIndex > 0 && nextIndex < text.Length - 1 && text[nextIndex] == ' ')
                        textAdder(" ", false);
                    else if (isPromptLine)
                        textAdder(Wrapper.PromptChar + "", false);

                    currentIndex = nextIndex + 1;
                } while (currentIndex < text.Length - 1 );
            }
            else
            {
                textAdder(text, true);
            }
            if (appendNewLine)
                textAdder(Environment.NewLine, false);

            box.ScrollToCaret();
        }


        private Entry ParseInputLine()
        {
            var commandText = textInput.Text;
            textInput.Text = "";

            return new Entry(History, "// TODO: get path", commandText);
        }

        private void ProcessLink(string linkText)
        {
            if (linkText.StartsWith("www."))
                linkText = HttpProtocol + linkText;

            if (linkText.StartsWith(HttpProtocol))
            {
                SysProcess.Start(new ProcessStartInfo("cmd", "/c start " + linkText));
            }
            else if (linkText.StartsWith(FileProtocol) && linkText.Length > FileProtocol.Length + 3)
            {
                var stripped = linkText.Substring(FileProtocol.Length);
                var pathIndex = stripped.IndexOf('/');
                if (pathIndex >= 0)
                {
                    stripped = stripped.Substring(pathIndex + 1);
                    stripped = HttpUtility.UrlDecode(stripped).Replace('/', Path.DirectorySeparatorChar);

                    if (linkText.IndexOf(' ') > 0)
                        stripped = string.Format("{0}{1}{0}", '"', stripped);

                    SysProcess.Start(new ProcessStartInfo("explorer.exe", stripped));
                }
            }

            IsControlKeyHold = false;
        }
    }
}
